var PropertyList = function(p){
	this.elem = document.createElement('div');
	p.appendChild(this.elem);
}

PropertyList.prototype.displayProp=function(obj){
	with(this){
		while ( elem.childNodes.length >= 1 )
	    {
		    elem.removeChild( elem.firstChild );
		} 
		for (prop in obj.props){
			var div = document.createElement('p');
			div.className = 'prop';
			var caption = document.createElement('span');
			caption.className = 'propcaption';
			caption.innerHTML = prop;
			var input = document.createElement('input');
			input.className = 'propinput';
			input.type = 'text';
			input.value = obj[prop];
			var f = function(myprop){
				input.addEventListener('change',function(e){
					obj[myprop] = e.target.value;
				},false)
			};
			f(prop);
			div.appendChild(caption);
			div.appendChild(input);
			elem.appendChild(div);
		}
	}
}


function Property(obj, name, defaultVal, isRevisionable, setter){
	var _val = defaultVal;
	if (setter) setter(defaultVal);
	var _isChanged = false;
	var propId = {};
	var getter = function(){
		return _val;
	};
	var raw_setter = setter?function(val){
		if (_val!=val){
			_isChanged = true;
			_val = val;
			setter(_val);
		}
	}:function(val){
		if (_val!=val){
			_isChanged = true;
			_val = val;
		}
	}
	if (isRevisionable){
		Object.defineProperty(obj, name, {
			get:getter,
			set:function(val){
				if (val!=_val){
					var oldVar = _clone(_val);
					var undoFunc = function(){
						raw_setter(oldVar);
					};
					var newVal = _clone(val);
					undoFunc.redo = function(){
						raw_setter(newVal);
					}
					undoFunc.id = propId;
					Revision.applyAction(undoFunc);
				}
			},
			enumerable:true
		});				
	}else{
		Object.defineProperty(obj, name, {
			get:getter,
			set:raw_setter,
			enumerable:true
		});
	}
	Object.defineProperty(obj, 'meta_'+name, {
		enumerable:false,
		value:{
			isChanged:function(){
				return _isChanged;
			},
			set_norev:raw_setter
		}
	});
	Storage.registerObj(obj._class, name, defaultVal);
}

function BindProperty(obj, prop, defaultVal, bObj, bProp, isRev){
	//bObj[bProp] = defaultVal;	
	Property(obj, prop, defaultVal, isRev, function(val){
		bObj[bProp] = val;
	});
	obj.addProp(prop);
}

function PointerProperty(obj, prop, isRev){
	
}

function ArrayProperty(obj, prop, isRev, adder, remover){
	var _val = {};
	var pushF = adder?function(webobj){
		_val[webobj.id] = webobj;
		adder(webobj);
	}:function(webobj){
		_val[webobj.id] = webobj;
	}
	var removeF = remover?function(webobj){
		remover(webobj);
		delete _val[webobj.id];
	}:function(webobj){
		delete _val[webobj.id];
	}
	if (isRev){
		obj[prop] = {
			push:function(webobj){
				var undoF = function(){
					removeF(webobj);
				}
				undoF.redo = function(){
					pushF(webobj);
				}
				undoF.id = {};
				Revision.applyAction(undoF);
			},
			remove:function(webobj){
				var undoF = function(){
					pushF(webobj);
				}
				undoF.redo = function(){
					removeF(webobj);
				}
				undoF.id = {};
				Revision.applyAction(undoF);
			}
		}
	}else{
		obj[prop] = {
			push:pushF,
			remove:removeF
		}
	}
	obj[prop].serialize = function(){
		var ret = {}
		for (webobj in _val){
			ret[webobj.id] = webobj.serialize();
		}
		ret._class = 'ArrayProperty';
		return ret;
	}
	obj[prop].deserialize = function(data){
		for (webobj in _val){
			ret[webobj.id] = webobj.deserialize();
		}
	}
	obj[prop].getList = function(){
		return _val;
	}
	obj.addProp(prop);
}
//logpush('Finish processing PropertyList');